#include <iostream>
#include <vector>
#include <memory>
#include <functional>
#include <unordered_map>
#include <unistd.h>

// 定时器任务的回调函数,即超时时执行的任务
using TaskFunc = std::function<void()>;
// 定时器对象销毁的回调函数
using ReleaseFunc = std::function<void()>;

// 定时器任务
class TimerTask
{
private:
    uint64_t _id;         // 定时器任务对象id
    uint32_t _timeout;    // 定时任务的超时时间
    bool _canceled;       // false表示没有被取消,true表示被取消了
    TaskFunc _task_cb;    // 定时器对象要执行的定时任务
    ReleaseFunc _release; // 用于删除TimerWheel中保存的定时器对象信息
public:
    TimerTask(const uint64_t &id, const uint32_t &delay, const TaskFunc &cb)
        : _id(id), _timeout(delay), _task_cb(cb), _canceled(false) {}
    ~TimerTask()
    {
        if (_canceled == false)
            _task_cb();
        _release();
    }

    void Canceled() { _canceled = true; }
    uint32_t DelayTime() { return _timeout; }
    void SetRelease(const ReleaseFunc &cb) { _release = cb; }
};

// 管理定时器任务的shared_ptr
using PtrTask = std::shared_ptr<TimerTask>; 
// 管理定时器任务的weak_ptr
using WeakTask = std::weak_ptr<TimerTask>;

// 时间轮
class TimerWheel
{
private:
    std::vector<std::vector<PtrTask>> _wheel;
    int _tick;     // 当前的秒针,走到哪里释放哪里,就相当于执行哪里的任务
    int _capacity; // 表盘的最大数量,即最大延迟时间
    std::unordered_map<uint64_t, WeakTask> _timers;

private:
    void RemoveTimer(const uint64_t &id)
    {
        auto it = _timers.find(id);
        if (it != _timers.end())
        {
            _timers.erase(it);
        }
    }

public:
    TimerWheel() : _tick(0), _capacity(60), _wheel(_capacity) {}
    // 添加定时任务
    void TimerAdd(const uint64_t &id, const uint32_t &delay, const TaskFunc &cb)
    {
        PtrTask ptr(new TimerTask(id, delay, cb));
        ptr->SetRelease(std::bind(&TimerWheel::RemoveTimer, this, id));
        int pos = (_tick + delay) % _capacity;
        // 将shared_ptr管理的对象加入到时间轮中
        _wheel[pos].push_back(ptr);
        // 将shared_ptr管理的对象的weak_ptr加入到哈希表中
        _timers[id] = WeakTask(ptr);
    }

    // 刷新/延迟定时时间
    void TimerRefresh(const uint64_t &id)
    {
        // 通过保存的定时器的weak_ptr构造一个shared_ptr出来,添加到轮子中
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return;
        }
        // lock获取weak_ptr管理的对象对应的shared_ptr
        PtrTask ptr = it->second.lock();
        int delay = ptr->DelayTime();
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(ptr);
    }

    // 取消定时任务
    void TimerCancel(const uint64_t &id)
    {
        auto it = _timers.find(id);
        // 没有找到定时任务就没法刷新和延迟,直接退出
        if (it == _timers.end())
            return;
        PtrTask ptr = it->second.lock();
        if (ptr)
            ptr->Canceled();
    }

    // 这个函数应该每秒钟被执行一次,相当于秒针向后走了一步
    void RunTimerTask()
    {
        _tick = (_tick + 1) % _capacity;
        // 清空指定位置的数组,就会把数组中保存的所有管理定时器对象的shared_ptr释放掉
        _wheel[_tick].clear();
    }
};

class Test
{
public:
    Test() { std::cout << "Test 构造" << std::endl; }
    ~Test() { std::cout << "Test 析构" << std::endl; }
};

void Release(const Test *t)
{
    delete t;
}

int main()
{
    TimerWheel tw;
    Test *t = new Test();
    tw.TimerAdd(100, 5, std::bind(Release, t));
    for (int i = 0; i < 5; i++)
    {
        sleep(1);
        // 刷新定时任务
        tw.TimerRefresh(100);
        // 向后移动指针
        tw.RunTimerTask();
        std::cout << "刷新了定时任务,需要在5秒钟之后进行销毁" << std::endl;
    }
    for (;;)
    {
        sleep(1);
        std::cout << "------------------" << std::endl;
        tw.RunTimerTask(); // 向后移动秒针
    }

    return 0;
}